iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
Modern Web

30天React練功坊-攻克常見實務/面試問題系列 第 6

30天React練功坊-攻克常見實務/面試問題 Day6: Rendered more hooks than during the previous render.

  • 分享至 

  • xImage
  •  
tags: ItIron2023 react

前言

我們昨天看了一個簡單的條件渲染的範例,了解到為什麼你不該用布林值以外的值作為判斷條件渲染的標準,今天我們繼續來看有關渲染的問題吧!

本日題目

請觀察這個codesandbox

day6-demo-image

day6-demo-image-error

題目中的程式碼相當單純,我們希望在某些條件下才去執行我們的useEffect hook,比方説使用者有登入的話才去抓資料之類的。

export default function App() {
  const [condition, setCondition] = useState(false);

  if (condition) {
    useEffect(() => {
      // Do something
    }, []);
  }

  return (
    <div>
      <h1>
        Uncaught Error: Rendered more hooks than during the previous render.
      </h1>
      <button onClick={() => setCondition(!condition)}>Toggle Condition</button>
    </div>
  );
}

請試著解釋錯誤發生的原因並修復這個錯誤。

解答與基本解釋

這也是實務上相當常見的錯誤之一,最根本的原因在於react本身的機制,react依賴hooks的執行順序去確保每個state的值在多個useState & useEffect的使用下仍能保持正確,因此他必須每一次都執行與前一次渲染相同的hooks數量,同類型的錯誤也會發生在條件渲染上,若你在某個hook前就return整個組件,那麼相同的錯誤也會發生,這也是為什麼react官方總是要你把hooks放在最上方使用。

理解這一點之後我想解法就不言自明了,我們只要確保hooks的執行數量是相同的,因此你只要將上方的程式碼略作調整即可。

export default function App() {
  const [condition, setCondition] = useState(false);

  
  useEffect(() => { // 將條件放進hooks內即可
    if (condition) {
        // Do something
    }
  }, []);

  return (
    <div>
      <h1>
        Uncaught Error: Rendered more hooks than during the previous render.
      </h1>
      <button onClick={() => setCondition(!condition)}>Toggle Condition</button>
    </div>
  );
}

總結

今天的題目相當單純,不過確實是個在實務上必須注意的細節,正確得使用hook能讓你開發的稍微有效率一些(是的,我說稍微,react本身的缺點也不在少數),了解錯誤發生的原因會讓你更知道該如何修復同類型的bug! 各位明天見囉!

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
30天React練功坊-攻克常見實務/面試問題 Day5 An unexpected "0" in the page while doing condition rendering
下一篇
30天React練功坊-攻克常見實務/面試問題 Day7: Memeory leak with useEffect
系列文
30天React練功坊-攻克常見實務/面試問題30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
lijun
iT邦新手 5 級 ‧ 2023-12-06 15:44:15

作者您好

在第一次進入畫面的時候只使用了useState
因為設置了if條件限制useEffect
點擊button後重新渲染畫面時卻使用了useState,useEffect
相比第一次多了一個useEffect 才會報錯

以下是我實作的程式碼

  useEffect(() => {
    if (condition) {
      console.log("123");  //不會印出123
    }
  }, []);

後來查詢了useEffect的用法
在useEffect內的if(condition) 只在第一次的渲染運行
所以如果[]沒有寫東西的話就只會判斷一次,再點一次button的話就不會判斷了

useEffect(() => {
  // 此處的代碼在組件第一次渲染時運行

  // 清理函數,例如取消訂閱或清理資源
  return () => {
    // 此處的代碼在組件卸載時運行
  };
}, []); // 空陣列表示只在組件第一次渲染時運行

lijun 雖然我並沒有很明白你的提問,不過看起來問題你自己已經有結論了。我稍微看了一下你的描述,感覺上你對於常見的react hooks還需要增加一些熟練度,當然這也是這系列文章想達到的目標,日後若你有發現內容有任何不正確/令人困惑的部分也歡迎你隨時提出,我會盡快回覆~!

lijun iT邦新手 5 級 ‧ 2023-12-06 18:02:49 檢舉

對 還在學習當中..感謝!

我要留言

立即登入留言